package com.inspur.edp.bff.core.filter;

import com.inspur.edp.bef.api.parameter.retrieve.RetrieveParam;
import com.inspur.edp.bff.api.exception.BffFrameworkException;
import com.inspur.edp.bff.api.exception.ErrorCodes;
import com.inspur.edp.bff.api.manager.IFSManager;
import com.inspur.edp.bff.api.manager.IFSManagerFactory;
import com.inspur.edp.bff.spi.VMHelpConfig;
import com.inspur.edp.bff.spi.helpextend.VmLinkedConfig;
import com.inspur.edp.bff.spi.helpextend.VmLinkedType;
import com.inspur.edp.cef.api.ICefValueGetter;
import com.inspur.edp.cef.api.ValueGetterConfig;
import com.inspur.edp.cef.entity.condition.EntityFilter;
import com.inspur.edp.cef.entity.condition.ExpressCompareType;
import com.inspur.edp.cef.entity.condition.ExpressRelationType;
import com.inspur.edp.cef.entity.condition.ExpressValueType;
import com.inspur.edp.cef.entity.condition.FilterCondition;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.spi.entity.resourceInfo.EntityResInfo;
import com.inspur.edp.web.help.api.LookupQueryParam;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

import java.util.ArrayList;
import java.util.Objects;

public class BeforeHelpLinkConvertor {
    public static void beforeHelpQuery(IFSManager manager, VMHelpConfig helpConfig, VmLinkedConfig vmLinkedConfig, LookupQueryParam queryParam) {
        String targetField = vmLinkedConfig.getTargetField();
        String filterField = getFilterField(targetField);
        String filterValue = getFilterValue(manager, helpConfig, vmLinkedConfig, queryParam);
        handleFilter(filterField, filterValue, vmLinkedConfig, queryParam);
    }

    private static void handleFilter(String filterField, String filterValue, VmLinkedConfig vmLinkedConfig, LookupQueryParam queryParam) {
        if (vmLinkedConfig.getLinkHelpType() == VmLinkedType.Normal)
            handleNormalFilter(filterField, filterValue, queryParam, vmLinkedConfig.isEnableFilterWhenConditionEmpty());
        else
            handleTreeFilter(filterField, filterValue, vmLinkedConfig, queryParam);
    }

    private static void handleTreeFilter(String filterField, String filterValue, VmLinkedConfig vmLinkedConfig, LookupQueryParam queryParam) {
        if (vmLinkedConfig.isPath()) {
            handlePathTree(vmLinkedConfig.getTreeField(), filterValue, vmLinkedConfig, queryParam);
            return;
        }
        handleParentTree(filterValue, vmLinkedConfig, queryParam);
    }

    private static void handleParentTree(String filterValue, VmLinkedConfig vmLinkedConfig, LookupQueryParam queryParam) {
        if (filterValue == null || "".equals(filterValue)) {
            handleParentFilterWithEmpty(vmLinkedConfig, filterValue, queryParam);
            return;
        }
        handleParentFilter(vmLinkedConfig.getTreeField(), filterValue, queryParam);

    }

    private static void handleParentFilterWithEmpty(VmLinkedConfig vmLinkedConfig, String filterValue, LookupQueryParam queryParam) {
        if (!vmLinkedConfig.isEnableFilterWhenConditionEmpty()) {
            return;
        }
        String parentFilterField = vmLinkedConfig.getTreeField() + "_ParentElement";
        if (queryParam.getFilter() == null)
            queryParam.setFilter(new EntityFilter());
        EntityFilter filter = queryParam.getFilter();
        if (filter.getFilterConditions() == null || filter.getFilterConditions().size() == 0) {
            filter.setFilterConditions(new ArrayList<FilterCondition>());
            FilterCondition filterCondition = getFilterCondition(0, parentFilterField, filterValue == null ? ExpressCompareType.Is : ExpressCompareType.Equal, filterValue, 0, ExpressRelationType.Empty, ExpressValueType.Value);
            filter.addFilterCondition(filterCondition);
            return;
        }
        FilterCondition filterCondition = getFilterCondition(1, parentFilterField, filterValue == null ? ExpressCompareType.Is : ExpressCompareType.Equal, filterValue, 1, ExpressRelationType.Empty, ExpressValueType.Value);
        ArrayList<FilterCondition> conditions = new ArrayList<>();
        conditions.add(filterCondition);
        filter.addFilterConditions(conditions);
    }

    private static void handleParentFilter(String filterField, String filterValue, LookupQueryParam queryParam) {
        String parentFilterField = filterField + "_ParentElement";
        if (queryParam.getFilter() == null)
            queryParam.setFilter(new EntityFilter());
        EntityFilter filter = queryParam.getFilter();
        if (filter.getFilterConditions() == null || filter.getFilterConditions().size() == 0) {
            filter.setFilterConditions(new ArrayList<FilterCondition>());
            FilterCondition filterCondition = getFilterCondition(0, parentFilterField, ExpressCompareType.Equal, filterValue, 0, ExpressRelationType.Empty, ExpressValueType.Value);
            filter.getFilterConditions().add(filterCondition);
            return;
        }
        FilterCondition filterCondition = getFilterCondition(1, parentFilterField, ExpressCompareType.Equal, filterValue, 1, ExpressRelationType.Empty, ExpressValueType.Value);
        ArrayList<FilterCondition> conditions = new ArrayList<>();
        conditions.add(filterCondition);
        filter.addFilterConditions(conditions);
    }

    private static FilterCondition getFilterCondition(int lBracketCount, String fieldName, ExpressCompareType compare, String value, int rBracketCount, ExpressRelationType relation, ExpressValueType expresstype) {
        FilterCondition filterCondition = new FilterCondition();
        filterCondition.setlBracketCount(lBracketCount);
        filterCondition.setFilterField(fieldName);
        filterCondition.setCompare(compare);
        filterCondition.setValue(value);
        filterCondition.setRBracketCount(rBracketCount);
        filterCondition.setRelation(relation);
        filterCondition.setExpresstype(expresstype);
        return filterCondition;
    }

    private static void handlePathTree(String filterField, String filterValue, VmLinkedConfig vmLinkedConfig, LookupQueryParam queryParam) {
        if (filterValue == null || "".equals(filterValue)) {
            handlePathFilterWithEmpty(queryParam, vmLinkedConfig);
            return;
        }
        handlePathFilter(filterField, filterValue, queryParam, vmLinkedConfig);
    }

    private static void handlePathFilterWithEmpty(LookupQueryParam queryParam, VmLinkedConfig vmLinkedConfig) {
        if (!vmLinkedConfig.isEnableFilterWhenConditionEmpty())
            return;
        String pathFilterField = vmLinkedConfig.getTreeField() + "_Path";
        String layerFilterField = vmLinkedConfig.getTreeField() + "_Layer";
        String pathValue = null;
        String layerValue = null;
        if (queryParam.getFilter() == null)
            queryParam.setFilter(new EntityFilter());
        EntityFilter filter = queryParam.getFilter();
        if (filter.getFilterConditions() == null || filter.getFilterConditions().size() == 0) {
            filter.setFilterConditions(new ArrayList<FilterCondition>());
            FilterCondition filterLayer = getFilterCondition(1, pathFilterField, ExpressCompareType.Is, pathValue, 0, ExpressRelationType.And, ExpressValueType.Value);
            FilterCondition filterPath = getFilterCondition(0, layerFilterField, ExpressCompareType.Is, layerValue, 1, ExpressRelationType.Empty, ExpressValueType.Value);
            ArrayList<FilterCondition> conditions = new ArrayList<>();
            conditions.add(filterLayer);
            conditions.add(filterPath);
            filter.addFilterConditions(conditions);
            return;
        }
        FilterCondition filterLayer = getFilterCondition(1, pathFilterField, ExpressCompareType.Is, pathValue, 0, ExpressRelationType.And, ExpressValueType.Value);
        FilterCondition filterPath = getFilterCondition(0, layerFilterField, ExpressCompareType.Is, layerValue, 1, ExpressRelationType.Empty, ExpressValueType.Value);
        ArrayList<FilterCondition> conditions = new ArrayList<>();
        conditions.add(filterLayer);
        conditions.add(filterPath);
        filter.addFilterConditions(conditions);
    }

    private static void handlePathFilter(String filterField, String filterValue, LookupQueryParam queryParam, VmLinkedConfig vmLinkedConfig) {
        String pathFilterField = filterField + "_Path";
        String layerFilterField = filterField + "_Layer";
        IFSManager manager = SpringBeanUtils.getBean(IFSManagerFactory.class).getFSManagerByVOId(vmLinkedConfig.getTargetVoId());
        RetrieveParam param = new RetrieveParam();
        param.setNeedLock(false);
        IEntityData data = manager.retrieve(filterValue, param);
        ICefData cefData = (ICefData) data.getValue(filterField);
        String path = cefData.getValue("Path").toString();
        Integer pathLayer = (Integer) cefData.getValue("Layer") + 1;
        String layer = pathLayer.toString();
        if (queryParam.getFilter() == null)
            queryParam.setFilter(new EntityFilter());
        EntityFilter filter = queryParam.getFilter();
        if (filter.getFilterConditions() == null || filter.getFilterConditions().size() == 0) {
            filter.setFilterConditions(new ArrayList<FilterCondition>());
            FilterCondition filterLayer = getFilterCondition(1, pathFilterField, ExpressCompareType.LikeStartWith, path, 0, ExpressRelationType.And, ExpressValueType.Value);
            FilterCondition filterPath = getFilterCondition(0, layerFilterField, ExpressCompareType.Equal, layer, 1, ExpressRelationType.Empty, ExpressValueType.Value);
            ArrayList<FilterCondition> conditions = new ArrayList<>();
            conditions.add(filterLayer);
            conditions.add(filterPath);
            filter.addFilterConditions(conditions);
            return;
        }
        FilterCondition filterLayer = getFilterCondition(1, pathFilterField, ExpressCompareType.LikeStartWith, path, 0, ExpressRelationType.And, ExpressValueType.Value);
        FilterCondition filterPath = getFilterCondition(0, layerFilterField, ExpressCompareType.Equal, layer, 1, ExpressRelationType.Empty, ExpressValueType.Value);
        ArrayList<FilterCondition> conditions = new ArrayList<>();
        conditions.add(filterLayer);
        conditions.add(filterPath);
        filter.addFilterConditions(conditions);
    }

    private static void handleNormalFilter(String filterField, String filterValue, LookupQueryParam queryParam, boolean enableFilterWhenConditionEmpty) {
        if (filterValue == null || "".equals(filterValue)) {
            addFilterConditionWithEmpty(filterValue, filterField, queryParam, enableFilterWhenConditionEmpty);
            return;
        }
        addFilterCondition(filterField, filterValue, queryParam);
    }

    private static void addFilterConditionWithEmpty(String filterValue, String filterField, LookupQueryParam queryParam, boolean enableFilterWhenConditionEmpty) {
        if (!enableFilterWhenConditionEmpty)
            return;
        if (queryParam.getFilter() == null)
            queryParam.setFilter(new EntityFilter());
        EntityFilter filter = queryParam.getFilter();
        if (filter.getFilterConditions() == null || filter.getFilterConditions().size() == 0) {
            filter.setFilterConditions(new ArrayList<FilterCondition>());
            FilterCondition filterCondition = getFilterCondition(0, filterField, filterValue == null ? ExpressCompareType.Is : ExpressCompareType.Equal, filterValue, 0, ExpressRelationType.Empty, ExpressValueType.Value);
            filter.getFilterConditions().add(filterCondition);
            return;
        }
        FilterCondition filterCondition = getFilterCondition(0, filterField, filterValue == null ? ExpressCompareType.Is : ExpressCompareType.Equal, filterValue, 0, ExpressRelationType.Empty, ExpressValueType.Value);
        ArrayList<FilterCondition> conditions = new ArrayList<>();
        conditions.add(filterCondition);
        filter.addFilterConditions(conditions);
    }

    private static void addFilterCondition(String filterField, String filterValue, LookupQueryParam queryParam) {
        if (queryParam.getFilter() == null)
            queryParam.setFilter(new EntityFilter());
        EntityFilter filter = queryParam.getFilter();
        if (filter.getFilterConditions() == null || filter.getFilterConditions().size() == 0) {
            filter.setFilterConditions(new ArrayList<FilterCondition>());
            FilterCondition filterCondition = getFilterCondition(0, filterField, ExpressCompareType.Equal, filterValue, 0, ExpressRelationType.Empty, ExpressValueType.Value);
            filter.getFilterConditions().add(filterCondition);
            return;
        }
        FilterCondition filterCondition = getFilterCondition(0, filterField, ExpressCompareType.Equal, filterValue, 0, ExpressRelationType.Empty, ExpressValueType.Value);
        ArrayList<FilterCondition> conditions = new ArrayList<>();
        conditions.add(filterCondition);
        filter.addFilterConditions(conditions);
    }

    private static String getFilterValue(IFSManager manager, VMHelpConfig helpConfig, VmLinkedConfig vmLinkedConfig, LookupQueryParam queryParam) {
        String sourceField = vmLinkedConfig.getSourceField();
        IEntityData data = getData(manager, vmLinkedConfig, queryParam);
        ICefValueGetter valueGetter = SpringBeanUtils.getBean(ICefValueGetter.class);
        ValueGetterConfig valueGetterConfig = new ValueGetterConfig();
        valueGetterConfig.setAssociationValue(true);
        valueGetterConfig.setSingleValueUdt(false);
        Object value = valueGetter.getValue(data, sourceField, valueGetterConfig);
        return value == null ? null : value.toString();
    }

    private static IEntityData getData(IFSManager manager, VmLinkedConfig vmLinkedConfig, LookupQueryParam param) {
        String relationFilterFieldInfo = param.getRelationFilterFieldInfo();
        String[] nodeInfo = relationFilterFieldInfo.split("/", 0);
        if (!vmLinkedConfig.isSourceFieldInChild()) {
            if (nodeInfo == null || nodeInfo.length == 0)
                throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1022);
            IEntityData rootData = manager.retrieve(nodeInfo[0], new RetrieveParam());
            return rootData;
        }
        ArrayList<String> roorIds = new ArrayList<>();
        ArrayList<String> nodeCodes = new ArrayList<>();
        initIdsAndNodeCodes(nodeInfo, roorIds, nodeCodes, vmLinkedConfig.getSourceObjCode());
        ArrayList<String> nodes = getTransNodeCode(manager, nodeCodes);
        IEntityData childData = manager.retrieveChild(nodes, roorIds, new RetrieveParam());
        return childData;
    }

    private static ArrayList<String> getTransNodeCode(IFSManager manager, ArrayList<String> nodeCodes) {
        ArrayList<String> nodes = new ArrayList<>();
        for (String nodeCode : nodeCodes) {
            String code = prefixLetterToUper(nodeCode);
            EntityResInfo info = manager.getModelInfo().getCustomResource(code);
            if (info != null && info.getEntityCode() != null && info.getEntityCode().equals("") == false)
                nodes.add(info.getEntityCode());
            else
                nodes.add(code);
        }
        return nodes;
    }

    public static String prefixLetterToUper(String str) {
        Objects.requireNonNull(str, "字符转换失败！");
        char[] cs = str.trim().toCharArray();
        if (Character.isUpperCase(cs[0]))
            return str;
        cs[0] -= 32;
        return String.valueOf(cs);
    }

    private static void initIdsAndNodeCodes(String[] nodeInfo, ArrayList<String> roorIds, ArrayList<String> nodeCodes, String sourceObjCode) {
        for (int i = 0; i < nodeInfo.length; i++) {
            if (i % 2 == 0)
                roorIds.add(nodeInfo[i]);
            else {
                if (nodeInfo[i].equalsIgnoreCase(sourceObjCode)) {
                    nodeCodes.add(nodeInfo[i]);
                    roorIds.add(nodeInfo[i + 1]);
                    break;
                }
                nodeCodes.add(nodeInfo[i]);
            }
        }
    }

    private static String getFilterField(String targetField) {
        return targetField;
    }
}
